package com.cdqidi.core.weixinmanager.service.wx;

import com.cdqidi.core.weixinmanager.domain.QrDTO;
import com.cdqidi.core.weixinmanager.domain.WxDTO;
import com.cdqidi.core.weixinmanager.util.QrUtil;
import com.cdqidi.dto.ApiResultWrapper;
import com.cdqidi.exception.ApiException;
import com.jfinal.weixin.sdk.api.ApiResult;
import com.jfinal.wxaapp.api.WxaQrcodeApi;
import com.jfinal.wxaapp.api.WxaUserApi;
import com.qd.upload.service.UploadServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Map;

/**
 * 〈一句话功能简述〉<br>
 *
 * @author sjk
 * @since 1.0.0
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class WxaApiService {

    private final UploadServiceImpl uploadService;
    private final WxDTO wxDto;

    /**
     * 获得小程序openid
     *
     * @param code 小程序前端传入
     * @return 微信返回
     */
    public ApiResultWrapper<Object> getWxaOpenId(String code) {
        final ApiResult apiResult = WxaUserApi.getSessionKey(code);
        if (apiResult.isSucceed()) {
            return com.cdqidi.dto.ApiResult.success(apiResult.getAttrs());
        }
        return com.cdqidi.dto.ApiResult.error(apiResult.getErrorCode(), apiResult.getErrorMsg());
    }

    /**
     * 生成葵花码永久有效 有次数限制，接口 createQRCode 加上接口 get，总共生成的码数量限制为 100,000，请谨慎调用。
     *
     * @param qrDto 前端对象
     * @return 错误返回错误码，成功返回存储葵花码绝对路径
     */
    @SneakyThrows
    public ApiResultWrapper<Object> crateQr(QrDTO qrDto) {
        final Integer width = qrDto.getWidth();
        final String path = qrDto.getPath();
        if (!StringUtils.hasLength(path)) {
            return com.cdqidi.dto.ApiResult.error("path不能为空");
        }
        final String qrPath = getQrPath(qrDto.getName());
        if (null != qrPath) {
            return com.cdqidi.dto.ApiResult.success(qrPath);
        }
        InputStream inputStream;
        if (null == width) {
            inputStream = WxaQrcodeApi.createQrcode(path);
        } else {
            inputStream = WxaQrcodeApi.createQrcode(path, width);
        }
        try (inputStream) {
            return saveQrImg(qrDto, inputStream, true);
        }

    }

    /**
     * 生成葵花码永久有效 有次数限制，接口 createQRCode 加上接口 get，总共生成的码数量限制为 100,000，请谨慎调用。
     * （不推荐使用）
     * 可接受 path 参数较长
     *
     * @param qrDto 前端对象
     * @return 错误返回错误码，成功返回存储葵花码绝对路径
     */
    @SneakyThrows
    public ApiResultWrapper<Object> getQrCode(QrDTO qrDto) {
        final String path = qrDto.getPath();
        final Boolean isHyAline = qrDto.getIsHyAline();
        final Boolean autoColor = qrDto.getAutoColor();
        final Integer width = qrDto.getWidth();
        final Map<String, String> lineColor = qrDto.getLineColor();
        if (!StringUtils.hasLength(path)) {
            return com.cdqidi.dto.ApiResult.error("path不能为空");
        }
        if (Boolean.FALSE.equals(autoColor)) {
            if (null == lineColor || lineColor.isEmpty()) {
                return com.cdqidi.dto.ApiResult.error("autoColor为false时，lineColor不能为空");
            }
        }
        final String qrPath = getQrPath(qrDto.getName());
        if (null != qrPath) {
            return com.cdqidi.dto.ApiResult.success(qrPath);
        }
        InputStream inputStream;
        if (Boolean.TRUE.equals(autoColor)) {
            inputStream = WxaQrcodeApi.get(path, width, isHyAline);
        } else {
            final String r = lineColor.get("r");
            final String g = lineColor.get("g");
            final String b = lineColor.get("b");
            if (!StringUtils.hasLength(r) || !StringUtils.hasLength(g) || !StringUtils.hasLength(b)) {
                return com.cdqidi.dto.ApiResult.error("r,g,b不能为空");
            }
            inputStream = WxaQrcodeApi.get(path, width, r, g, b, isHyAline);
        }
        try (inputStream) {
            return saveQrImg(qrDto, inputStream, true);
        }
    }

    /**
     * 获取小程序码，适用于需要的码数量极多的业务场景。通过该接口生成的小程序码，永久有效，数量暂无限制,5000次/分钟
     * 可接受页面参数较短
     *
     * @param qrDto 前端对象
     * @return 错误返回错误码，成功返回存储葵花码绝对路径
     */
    @SneakyThrows
    public ApiResultWrapper<Object> getUnlimited(QrDTO qrDto) {
        final String page = qrDto.getPage();
        final Integer width = qrDto.getWidth();
        final String scene = qrDto.getScene();
        final Boolean autoColor = qrDto.getAutoColor();
        final Map<String, String> lineColor = qrDto.getLineColor();
        final Boolean isHyAline = qrDto.getIsHyAline();
        if (!StringUtils.hasLength(page)) {
            return com.cdqidi.dto.ApiResult.error("page不能为空");
        }
        if (!StringUtils.hasLength(scene)) {
            return com.cdqidi.dto.ApiResult.error("scene不能为空");
        }
        if (Boolean.FALSE.equals(autoColor)) {
            if (null == lineColor || lineColor.isEmpty()) {
                return com.cdqidi.dto.ApiResult.error("autoColor为false时，lineColor不能为空");
            }
        }
        InputStream inputStream;
        if (Boolean.TRUE.equals(autoColor)) {
            inputStream = WxaQrcodeApi.getUnLimit(scene, page, width, isHyAline);
        } else {
            final String r = lineColor.get("r");
            final String g = lineColor.get("g");
            final String b = lineColor.get("b");
            if (!StringUtils.hasLength(r) || !StringUtils.hasLength(g) || !StringUtils.hasLength(b)) {
                return com.cdqidi.dto.ApiResult.error("r,g,b不能为空");
            }
            inputStream = WxaQrcodeApi.getUnLimit(scene, page, width, r, g, b, isHyAline);
        }
        try (inputStream) {
            return saveQrImg(qrDto, inputStream, true);
        }

    }


    /**
     * 保存二维码
     *
     * @param qrDto            前端对象
     * @param inputStream      流
     * @param isSaveQrBasePath 是的话存储到QrBasePath路径，不散列，只有有数量限制的二维码才是用这个
     * @return 路径
     */
    private ApiResultWrapper<Object> saveQrImg(QrDTO qrDto, InputStream inputStream, boolean isSaveQrBasePath) {
        if (null == inputStream) {
            return com.cdqidi.dto.ApiResult.error("生成二维码失败");
        }
        String fileName = qrDto.getName() + ".jpg";
        try {
            if (isSaveQrBasePath) {
                String basePath = wxDto.getQrBasePath();
                QrUtil.saveToImgByInputStream(inputStream, basePath, fileName);
                return com.cdqidi.dto.ApiResult.success(fileName);
            } else {
                return com.cdqidi.dto.ApiResult.success(uploadService.saveWxPic(fileName, inputStream));
            }
        } catch (IOException e) {
            throw new ApiException(e);
        }
    }

    private String getFilePath(String path, String fileName) {
        if (StringUtils.hasLength(path)) {
            path = path.replace("\\", "/");
            String imgDomain = wxDto.getQrDownloadPath();
            return imgDomain + "?path=" + URLEncoder.encode(path, StandardCharsets.UTF_8) + "&fileName=" + URLEncoder.encode(fileName, StandardCharsets.UTF_8);
        } else {
            path = "";
        }
        return path;
    }

    /**
     * @param fileName 文件名
     * @return 存在返回文件绝对路径，不存在返回空
     */
    private String getQrPath(String fileName) {
        final String basePath = wxDto.getQrBasePath();
//        final String downloadPath = wxDto.getQrDownloadPath();
        final boolean b = QrUtil.isFileExists(basePath, fileName + ".jpg");
        if (b) {
//            return downloadPath + File.separator + fileName + ".jpg";
            return fileName + ".jpg";
        }
        return null;
    }
}